package mini.compiler;

import mini.Program;

/** 
 * This is a convenience class that can be used for generating
 * RAL code.
 * 
 * @author Jennifer
 *
 */
public class CodeGenerator {

	// Build up code here
	private StringBuilder code = new StringBuilder();
	
	// Do we need to insert a newline befre adding the next code line?
	private static boolean needNewline = false;
	
	public CodeGenerator() {
	}
	
	/**
	 * LDA <variable>
	 * @param variable
	 */
	public void addLoadAccumulator( String variable ) {
		if( needNewline ) {
			appendNewline();
		}
		code.append( "LDA " + variable );
		needNewline = true;
	}
	
	/**
	 * LDI <variable>
	 * @param variable
	 */
	public void addLoadIndirect( String variable ) {
		if( needNewline ) {
			appendNewline();
		}
		code.append( "LDI " + variable );
		needNewline = true;
	}
	
	/**
	 * STA <variable>
	 * @param variable
	 */
	public void addStoreAccumulator( String variable ) {
		if( needNewline ) {
			appendNewline();
		}
		code.append( "STA " + variable );
		needNewline = true;
	}
	
	/**
	 * STI <variable>
	 * @param variable
	 */
	public void addStoreIndirect( String variable ) {
		if( needNewline ) {
			appendNewline();
		}
		code.append( "STI " + variable );
		needNewline = true;
	}
	
	/**
	 * SUB <variable>
	 * @param variable
	 */
	public void addSubtract( String variable ) {
		if( needNewline ) {
			appendNewline();
		}
		code.append( "SUB " + variable );
		needNewline = true;
	}
	
	/**
	 * ADD <variable>
	 * @param variable
	 */
	public void addAdd( String variable ) {
		if( needNewline ) {
			appendNewline();
		}
		code.append( "ADD " + variable );
		needNewline = true;
	}
	
	/**
	 * MUL <variable>
	 * @param variable
	 */
	public void addMultiply( String variable ) {
		if( needNewline ) {
			appendNewline();
		}
		code.append( "MUL " + variable );
		needNewline = true;
	}
	
	/**
	 * JMP <variable>
	 * Unconditional Jump
	 * @param variable
	 */
	public void addJMP( String variable ) {
		if( needNewline ) {
			appendNewline();
		}
		code.append( "JMP " + variable );
		needNewline = true;
	}
	
	/**
	 * JMZ <variable>
	 * Jump on Zero
	 * @param variable
	 */
	public void addJMZ( String variable ) {
		if( needNewline ) {
			appendNewline();
		}
		code.append( "JMZ " + variable );
		needNewline = true;
	}
	
	/**
	 * JMN <variable>
	 * Jump on Negative
	 * @param variable
	 */
	public void addJMN( String variable ) {
		if( needNewline ) {
			appendNewline();
		}
		code.append( "JMN " + variable );
		needNewline = true;
	}
	
	/**
	 * HLT <variable>
	 */
	public void addHalt() {
		if( needNewline ) {
			appendNewline();
		}
		code.append( "HLT" );
		needNewline = true;
	}
	
	/***
	 * Add label
	 */
	public void addLabel(String variable){
		if( needNewline ){
			appendNewline();
		}
		code.append(variable + ": ");
		needNewline=false;
	}
	
	/**
	 * Appends a chunk of code to what we're building up
	 * @param newCode
	 */
	public void appendCode( String newCode ) {
		if( needNewline ) {
			appendNewline();
		}
		code.append( newCode );
		needNewline = true;
	}
	
	/**
	 * Add a newline
	 */
	private void appendNewline() {
		code.append( Program.NEWLINE );
		needNewline = false;
	}
	
	/**
	 * Return the built up code as a string
	 */
	public String getCode() {
		return code.toString();
	}

	@Override
	public String toString() {
		return getCode();
	}
	
	/**
	 * Given some instruction (LDA, JMP, etc) return true if
	 * it's a jump instruction (i.e., one that would take, in its
	 * symbolic form, some sort of location referene) and false
	 * otherwise (i.e., one that would take, in its symbolic form,
	 * a reference from the symbol table) 
	 * @return True if it's a jump instruction, false otherwise
	 */
	public static boolean isJumpInstruction( String instruction ) {
		if( instruction == null ) {
			return false;
		}
		return( instruction.equals("JMP") || 
				instruction.equals("JMZ") ||
				instruction.equals("JMN") );
	}

	/**
	 * Given some instruction (LDA, JMP, etc) return true if
	 * it needs an operand
	 * @return True if it needs an operand, false otherwise
	 */
	public static boolean needsOperand( String instruction ) {
		
		// I guess null instructions don't need operands...
		if( instruction == null ) {
			return false;
		}
		
		// Everything but a halt needs an operand
		return !instruction.equals("HLT");
	}
}
